home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Tech Arsenal 1
/
Tech Arsenal (Arsenal Computer).ISO
/
tek-05
/
pcb121.zip
/
WD8003E.INC
< prev
Wrap
Text File
|
1992-01-23
|
19KB
|
496 lines
;;******************************************************************************
;; wd8003e.inc wd8003e.inc
;;******************************************************************************
;;
;; Copyright (C) 1989 Northwestern University, Vance Morrison
;;
;;
;; Permission to view, compile, and modify for LOCAL (intra-organization)
;; USE ONLY is hereby granted, provided that this copyright and permission
;; notice appear on all copies. Any other use by permission only.
;;
;; Northwestern University makes no representations about the suitability
;; of this software for any purpose. It is provided "as is" without expressed
;; or implied warranty. See the copywrite notice file for complete details.
;;
;;******************************************************************************
;; wd8003 holds the interface routines for the western digital ethernet card
;; WD8003E or the starlan card WD8003S. Althougth this routine will work
;; for any of the above cards, it has been optimized for the Ethernet card.
;;
;; The functions provided by this file are
;;
;; WDE_DECLARE name,io_address,shr_seg,shr_off,promiscuous,total_pgs,bits16
;; WDE_DEFINE name
;; WDE_IF_R_ACCESS_out_BX_CX_ES name, no_packet
;; WDE_IF_R_CONT_in_BX_CX_ES_const_BX_CX_DX_BP_SI_DI_ES name, ok
;; WDE_IF_R_FREE_const_BX_CX_BP_SI_DI_ES name
;; WDE_IF_W_ACCESS_in_CX_out_DI_ES_const_BX_CX_BP name, no_buffer
;; WDE_IF_W_WRITE_in_CX_const_BX_BP_ES name
;; WDE_IF_SET_ADDRESS_in_SI_const_BX_CX_BP_DI_ES name
;; WDE_IF_COPY_in_CX_SI_DI_ES_out_SI_DI_const_BX_BP_ES name
;;
;; Variables set by this module
;;
;; wde_&name&_declared ;; one if this interface exists
;; if_&name&_address ;; the hardware address
;; if_&name&_mtu ;; the maximum trans unit
;;
;;******************************************************************************
include wd.inc
;;******************************************************************************
;; data storage needed by this module
wde_data STRUC
wde_new_bndry DB 0
wde_data ENDS
;;******************************************************************************
;; IF_DECLARE name, io_address, shr_seg, shr_off
;; declares an interface object. 'io_address' is the address of the
;; start of the 8003E control registers. 'shr_seg' and
;; 'shr_off' is the address of the WD8003 card buffer
;; This address must be a multiple of 512. If 'promiscuous' is not
;; zero (or blank),the interface is configured so that every packet on
;; the ethernet is received. 'total_pg' if not blank, is the total
;; amount of pages of shared memory. (default = 32 pages = 8K)
;; if 'bits16' is non-blank and equal to 1, then the card is assumed
;; to be a WD8013EBT card. It it is 2, then it is a WD8013 card but
;; we have disabled 16bit transfers (some hardware doesn't like it)
;;
WDE_DECLARE MACRO name, io_address, shr_seg, shr_off, promiscuous, total_pg, bits16
.errb <name>
.errb <io_address>
.errb <shr_seg>
.errb <shr_off>
.DATA
wde_&name&_declared = 1
wde_&name&_io = io_address ;; set compile time values
wde_&name&_shared_off = shr_off
wde_&name&_shared_seg = shr_seg
if shr_seg lt 8000h
.err Shared memory MUST be above 80000H
endif
wde_&name&_stop_pg = STOP_PG
ifnb <total_pg>
wde_&name&_stop_pg = 0&total_pg
endif
wde_&name&_promiscuous = 0
ifnb <promiscuous>
wde_&name&_promiscuous = 0&promiscuous
endif
wde_&name&_bits16 = 0
ifnb <bits16>
wde_&name&_bits16 = 0&bits16
endif
if wde_&name&_bits16 eq 1
;; note these can only touch registers AX and DX
WDE_16BIT_ON MACRO myname
mov AL,LAN16ENB or LA19 or MEM16ENB
WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES LAAR, wde_&&myname&&_io
ENDM
WDE_16BIT_OFF MACRO myname
mov AL,LAN16ENB or LA19
WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES LAAR, wde_&&myname&&_io
ENDM
MEM_DECLARE_16BIT WDE_16BIT_ON, WDE_16BIT_OFF, name
else
MEM_DECLARE_8BIT
endif
if_&name&_mtu = 1514
global wde_&name&_data:wde_data
global if_&name&_address:word
.CODE
global wde_&name&_real_define:near
ENDM
;;******************************************************************************
;; IF_DEFINE name
;; sets asside memory an name object and initializes it. This
;; routine is a no-op if 'name' was not declared
;;
WDE_DEFINE MACRO name
ifdef wde_&name&_declared
call wde_&name&_real_define
endif
ENDM
WDE_REAL_DEFINE MACRO name
LOCAL loop1, loop2, loop3, around, resetwait
.errb <name>
ifdef wde_&name&_declared
.DATA
if_&name&_address DW 3 DUP (0)
wde_&name&_data wde_data <> ;; create storage needed
.CODE
wde_&name&_real_define:
mov cx, 6 ;; get the ethernet address
mov bx, OFFSET if_&name&_address
mov dx, wde_&name&_io+ADDROM ;; point to the Ethernet address ROM
loop1:
in AL, DX
mov [BX], AL
inc DX
inc BX
loop loop1
mov AL, 80h ;; reset the card
WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES 0, wde_&name&_io
mov AL, 00h
WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES 0, wde_&name&_io
;; this sets bit 6 (0 justified) of register offset 0x05, it will enable
;; the lan controller to access shared RAM 16 bits at a time
;; In addition, this routine maintains address bit 19
;; (previous cards assumed this bit high...we must do it manually)
;; note: this is a write only register and only exists on the WD8013
if wde_&name&_bits16 eq 1
mov AL, LAN16ENB + LA19 ; set bit19 of address and 16 bit mode for card
WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES LAAR, wde_&name&_io
endif
;; register 0 is the MSR (Memory base reg)
;; this will enable the on board ram
mov AL, (wde_&name&_shared_seg+(wde_&name&_shared_off/16))/512
WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES 0, wde_&name&_io
mov AL, MSK_STP + MSK_PG0 + MSK_RD2 ;; RESET, goto page 0
WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES CMDR, wde_&name&_io
xor AL, AL ;; clear RBCR0,1
WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES RBCR0, wde_&name&_io
WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES RBCR1, wde_&name&_io
resetwait: ;; make sure reset is complete
READ_PORT_out_AL_const_BX_CX_BP_SI_DI_ES ISR, wde_&name&_io
test AL, MSK_RST
jz resetwait
mov AL, MSK_BMS + MSK_FT10 ;; select FIFO threshold = 8 bytes
if wde_&name&_bits16 eq 1
or AL, MSK_WTS ;; FOR 16 BIT OPERATION
endif
WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES DCR, wde_&name&_io
xor AL, AL ;; turn off receiving
WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES RCVR, wde_&name&_io
mov AL, MSK_LBm1 ;; enter loopback operation mode 1
WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES TCR, wde_&name&_io
mov AL, STRT_PG ;; start of input buffer (in 256b pages)
WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES PSTART, wde_&name&_io
mov AL, wde_&name&_stop_pg ;; end of input buffer (in 256b pages)
WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES PSTOP, wde_&name&_io
mov AL, STRT_PG
WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES BNRY, wde_&name&_io
mov AL, -1 ;; clear all status bits
WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES ISR, wde_&name&_io
mov AL, 0 ;; no interupts
WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES IMR, wde_&name&_io
mov AL, MSK_STP + MSK_PG1 + MSK_RD2 ;; make sure we are on page 1
WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES CMDR, wde_&name&_io
mov CX, 6 ;; set the ethernet address
mov BX, OFFSET if_&name&_address
mov DX, wde_&name&_io+PAR0
loop2:
mov AL, [BX] ;; get 1 byte into AL
out DX, AL ;; write to PAR
inc BX
inc DX
loop loop2
if wde_&name&_promiscuous ne 0
mov AL, 0FFH
else
xor AL, AL
endif
mov CX, 8 ;; set the multicast address to all 0's
mov DX, wde_&name&_io+MAR0
loop3:
out DX, AL
inc DX
loop loop3
mov AL, STRT_PG+1 ;; Set input pointer for queue
WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES CURR, wde_&name&_io
mov AL, MSK_STA + MSK_PG0 + MSK_RD2 ;; make sure we are on page 0
;; and start the NIC 8390
WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES CMDR, wde_&name&_io
xor AL, AL ;; loopback off
WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES TCR, wde_&name&_io
;; set receiver mode
if wde_&name&_promiscuous ne 0
mov AL, MSK_AB+MSK_AM+MSK_PRO ;; promiscuous
else
mov AL, MSK_AB ;; just broadcasts + to me
endif
WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES RCVR, wde_&name&_io
RET
endif
ENDM
;;******************************************************************************
;; IF_R_ACCESS_out_BX_ES name, no_packet
;; IF_R_ACCESS waits for the next packet to come from the the board
;; associated with 'name' and returns a pointer to the begining of
;; an ethernet packet in BX:ES. CX holds the length of the packet
;; R_ACCESS jumps to 'no_packet' if there are no packets waiting to
;; be read in
;;
WDE_IF_R_ACCESS_out_BX_CX_ES MACRO name, no_packet
local inside, good_packet, wrapped, new_wrapped, bad_packet, ok_status
local good_length, truncate
.errb <no_packet>
mov AL, MSK_PG0 + MSK_RD2 ;; read the BNRY register into AL
WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES CMDR, wde_&name&_io
READ_PORT_out_AL_const_BX_CX_BP_SI_DI_ES BNRY, wde_&name&_io
inc AL ;; increment with wrap around
cmp AL, wde_&name&_stop_pg
jb inside
mov AL, STRT_PG
inside:
mov BH, AL ;; save it in BH
mov AL, MSK_PG1 + MSK_RD2 ;; read CURR register into AL
WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES CMDR, wde_&name&_io
READ_PORT_out_AL_const_BX_CX_BP_SI_DI_ES CURR, wde_&name&_io
cmp AL, BH
je no_packet
xor BL, BL ;; BX now holds pointer to packet
mov DX, wde_&name&_shared_seg ;; ES = segment address
mov ES, DX
mov AH, ES:[BX+wde_&name&_shared_off] ;; get the status
cmp AH, SMK_PRX ;; is it good
jz ok_status
cmp AH, SMK_PRX+SMK_PHY
jnz bad_packet
ok_status:
mov AH, ES:[BX+1+wde_&name&_shared_off] ;; pointer to the next packet
;; sanity check on next packet pointer AH
cmp BH, AL ;; is BNDRY+1 <= CURR?
ja wrapped
cmp AH, BH
jb bad_packet
cmp AH, AL
jbe good_packet
jmp bad_packet
wrapped:
cmp AH, BH
jb new_wrapped
cmp AH, wde_&name&_stop_pg
jnb bad_packet
jmp good_packet
new_wrapped:
cmp AH, STRT_PG
jb bad_packet
cmp AH, AL
jbe good_packet
bad_packet:
;; set BNDRY = BNDRY+1 and try again
mov AL, MSK_PG0 + MSK_RD2 ;; make sure we are on page 0
WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES CMDR, wde_&name&_io
mov AL, BH ;; write the new BNRY register
WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES BNRY, wde_&name&_io
jmp no_packet ;; return bad status
good_packet:
mov wde_&name&_data.wde_new_bndry, AH ;; save it for R_FREE
mov CX, ES:[BX+wde_&name&_shared_off+2] ;; load the length
add BX, wde_&name&_shared_off+4 ;; BX point to begining of the packet
sub CX, 4
cmp CX, 1536 ;; sanity check
jle good_length
cmp CH, CL
jne truncate
xor CH, CH ;; fix western digital bug
jmp good_length
truncate:
mov CX, 1536
good_length:
ENDM
;;******************************************************************************
;; IF_R_FREE_const_BX_CX_BP_SI_DI_ES name
;; After the client is through processing the packet returned by
;; IF_R_ACCESS, IF_R_FREE must be called to inform 'name' that the
;; memory that the packet was in can be reused for future packets.
;;
WDE_IF_R_FREE_const_BX_CX_BP_SI_DI_ES MACRO name
local inside
.errb <name>
mov AL, MSK_PG0 + MSK_RD2 ;; make sure we are on page 0
WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES CMDR, wde_&name&_io
mov AL, wde_&name&_data.wde_new_bndry ;; Retreive NEW_BOUNDRY
dec AL
cmp AL, STRT_PG
jge inside
mov AL, wde_&name&_stop_pg-1
inside: ;; write the new BNRY register
WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES BNRY, wde_&name&_io
ENDM
;;******************************************************************************
;; WDE_IF_R_CONT_in_BX_CX_ES name, ok
;; IF_R_CONT determines if the packet returned by R_READ in BX:ES
;; of length CX is continuous. If it is it jumps to 'ok' otherwise
;; it just returns
;;
WDE_IF_R_CONT_in_BX_CX_ES_const_BX_CX_DX_BP_SI_DI_ES MACRO name, ok
.errb <ok>
mov AX, BX
add AX, CX
cmp AX, OFFSET wde_&name&_shared_off+wde_&name&_stop_pg*256
jb ok
ENDM
;;******************************************************************************
;; IF_W_ACCESS_in_CX_out_DI_ES name, no_buffer
;; IF_W_ACCESS returns a pointer to an output buffer for a packet. The
;; pointer is returned in DI:ES. If the ouptut buffer is busy, this
;; routine will jump to 'no_buffer'. The output buffer min(CX, 1536)
;; bytes long
;;
WDE_IF_W_ACCESS_in_CX_out_DI_ES_const_BX_CX_BP MACRO name, no_buffer
local wait_loop
.errb <no_buffer>
mov DI, 65000 ;; so we don't wait forever
wait_loop:
dec DI
jz no_buffer
READ_PORT_out_AL_const_BX_CX_BP_SI_DI_ES CMDR, wde_&name&_io
test AL, MSK_TXP
jnz wait_loop
mov DI, wde_&name&_shared_off ;; return DI:ES pointer
mov DX, wde_&name&_shared_seg
mov ES, DX
ENDM
;;******************************************************************************
;; IF_W_WRITE_in_CX name
;; IF_W_WRITE actually signals the ethernet board to write a packet to
;; the ethernet. The packet is assumed to be in the buffer returned by
;; IF_W_ACCESS. CX is the length of the packet to send.
;;
WDE_IF_W_WRITE_in_CX_const_BX_BP_ES MACRO name
.errb <name>
mov AL, MSK_PG0 + MSK_RD2 ;; make sure we are in register page 0
WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES CMDR, wde_&name&_io
mov AL, CL ;; set length
WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES TBCR0, wde_&name&_io
mov AL, CH
WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES TBCR1, wde_&name&_io
xor AL, AL ;; tell card packet begins at page 0
WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES TPSR, wde_&name&_io
mov AL, MSK_TXP + MSK_RD2 ;; send the packet
WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES CMDR, wde_&name&_io
ENDM
;;******************************************************************************
;; IF_SET_ADDRESS_in_SI name
;; IF_SET_ADDRESS_in_SI sets the hardware address to be the value
;; pointed to by SI. Note this function may be a no-op if the
;; hardware address cannot be set (ETHERNET for example)
;;
WDE_IF_SET_ADDRESS_in_SI_const_BX_CX_BP_DI_ES MACRO name
.err ;; we don't support setting ethernet addresses (yet)
ENDM
;;******************************************************************************
;; IF_COPY_in_CX_SI_DI_ES_out_SI_DI name
;; IF_COPY_in_CX_SI_DI_ES copys a packet from the input buffer (pointed
;; to by SI and the segement register given in IF_DECLARE) to an output
;; buffer (pointed to by DI and dest_reg) of length CX. It assumes the
;; output buffer is contiguous. (and the caller shouln't care if the
;; input buffer is contiguous)
;;
WDE_IF_COPY_in_CX_SI_DI_ES_out_SI_DI_const_BX_BP_ES MACRO name
local wrap, done, no_time1, no_time2
.errb <name>
mov DX, DS ;; save DS
mov AX, wde_&name&_shared_seg
mov DS, AX
mov AX, OFFSET wde_&name&_shared_off+wde_&name&_stop_pg*256
sub AX, SI ;; AX holds length to wrap line
cmp AX, CX
jl wrap ;; wrap if AX less than packet lenght
MEM_COPY_in_CX_SI_DI_ES_out_SI_DI_const_AX_BX_DX_BP_ES
jmp done
wrap:
xchg AX, CX ;; length is now length to wrap line
sub AX, CX ;; AX holds remainder
MEM_COPY_in_CX_SI_DI_ES_out_SI_DI_const_AX_BX_DX_BP_ES
mov SI, OFFSET wde_&name&_shared_off+STRT_PG*256
mov CX, AX
MEM_COPY_in_CX_SI_DI_ES_out_SI_DI_const_AX_BX_DX_BP_ES
done:
mov DS, DX ;; restore DS
ENDM
;;******************************************************************************
;; utility functions needed only within this module
READ_PORT_out_AL_const_BX_CX_BP_SI_DI_ES MACRO port, if_io
mov DX, if_io+port
in AL, DX ;; AL contains data read from port
ENDM
;;******************************************************************************
WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES MACRO port, if_io
mov DX, if_io+port
out DX, AL ;; AL contains data read from port
ENDM